<template>
  <div ref="graphContainer" class="knowledge-graph-container"></div>
</template>

<script>
import * as d3 from 'd3'
import { ref, onMounted, watch, onUnmounted } from 'vue'

export default {
  props: {
    // 直接接收图谱数据，不再通过subject获取
    graphData: {
      type: Object,
      default: () => ({
        nodes: [],
        links: []
      })
    },
    // 兼容旧的subject属性
    subject: {
      type: String,
      default: 'math'
    }
  },
  setup(props) {
    const graphContainer = ref(null)
    const localGraphData = ref(null)
    const simulation = ref(null)

    // Mock data structure (在没有传入数据时使用)
    const mockKnowledgeGraphs = {
      math: {
        nodes: [
          { id: '1', name: '代数', level: 'basic', score: 0.8 },
          { id: '2', name: '几何', level: 'basic', score: 0.7 },
          { id: '3', name: '函数', level: 'intermediate', score: 0.6 },
          { id: '4', name: '三角函数', level: 'intermediate', score: 0.5 },
          { id: '5', name: '微积分', level: 'advanced', score: 0.4 },
          { id: '6', name: '概率统计', level: 'advanced', score: 0.3 }
        ],
        links: [
          { source: '1', target: '3', relation: 'prerequisite' },
          { source: '2', target: '3', relation: 'related' },
          { source: '3', target: '4', relation: 'prerequisite' },
          { source: '4', target: '5', relation: 'prerequisite' },
          { source: '3', target: '6', relation: 'related' },
          { source: '1', target: '6', relation: 'related' }
        ]
      },
      physics: {
        nodes: [
          { id: '1', name: '力学', level: 'basic', score: 0.7 },
          { id: '2', name: '热学', level: 'basic', score: 0.6 },
          { id: '3', name: '电磁学', level: 'intermediate', score: 0.5 }
        ],
        links: [
          { source: '1', target: '2', relation: 'related' },
          { source: '1', target: '3', relation: 'prerequisite' }
        ]
      }
    }

    const loadGraphData = () => {
      // 优先使用传入的graphData
      if (props.graphData && props.graphData.nodes && props.graphData.nodes.length > 0) {
        console.log('使用传入的图谱数据:', props.graphData);

        // 深拷贝数据，确保不会修改原始数据
        localGraphData.value = JSON.parse(JSON.stringify(props.graphData));

        // 确保节点的id是字符串类型
        localGraphData.value.nodes = localGraphData.value.nodes.map(node => {
          return {
            ...node,
            id: String(node.id), // 确保id是字符串
            score: node.score !== undefined ? node.score : 0.7,
            level: node.level || (node.category === 'course' ? 'advanced' :
                                node.category === 'chapter' ? 'intermediate' : 'basic')
          };
        });

        // 确保链接的source和target是字符串类型
        localGraphData.value.links = localGraphData.value.links.map(link => {
          return {
            ...link,
            source: String(link.source),
            target: String(link.target),
            relation: link.relation || 'related'
          };
        });
      } else {
        // 回退到使用subject的mock数据
        console.log('使用mock数据:', props.subject);
        localGraphData.value = JSON.parse(JSON.stringify(
          mockKnowledgeGraphs[props.subject] || mockKnowledgeGraphs.math
        ));
      }

      console.log("处理后的图谱数据:", localGraphData.value);
    }

    const renderGraph = () => {
      if (!localGraphData.value || !graphContainer.value) {
        console.warn("无法渲染图谱：数据或容器不存在");
        return;
      }

      // 如果节点不存在或为空，显示空提示
      if (!localGraphData.value.nodes || localGraphData.value.nodes.length === 0) {
        console.warn("无法渲染图谱：节点数据为空");
        d3.select(graphContainer.value)
          .append("div")
          .attr("class", "empty-graph-message")
          .text("暂无知识图谱数据");
        return;
      }

      // 清空之前的图形
      d3.select(graphContainer.value).selectAll('*').remove()

      const width = graphContainer.value.clientWidth || 600
      const height = graphContainer.value.clientHeight || 400

      // 创建SVG
      const svg = d3.select(graphContainer.value)
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .attr('viewBox', [0, 0, width, height])

      const g = svg.append('g');

      // 创建模拟引擎
      if (simulation.value) {
        simulation.value.stop(); // 停止之前的模拟
      }

      // 安全检查：确保所有链接的源节点和目标节点都存在
      const nodeIds = new Set(localGraphData.value.nodes.map(n => n.id));
      const validLinks = localGraphData.value.links.filter(link =>
        nodeIds.has(String(link.source)) && nodeIds.has(String(link.target))
      );

      if (validLinks.length === 0 && localGraphData.value.nodes.length > 0) {
        console.warn("无有效链接，但有节点数据。创建默认链接以形成树状结构。");
        // 创建简单的树状结构链接
        if (localGraphData.value.nodes.length > 1) {
          const rootNode = localGraphData.value.nodes[0];
          for (let i = 1; i < localGraphData.value.nodes.length; i++) {
            validLinks.push({
              source: String(rootNode.id),
              target: String(localGraphData.value.nodes[i].id),
              relation: 'related'
            });
          }
        }
      }

      console.log("有效链接数:", validLinks.length);

      simulation.value = d3.forceSimulation(localGraphData.value.nodes)
        .force('link', d3.forceLink(validLinks)
          .id(d => String(d.id))
          .distance(120))
        .force('charge', d3.forceManyBody().strength(-400))
        .force('center', d3.forceCenter(width / 2, height / 2))
        .force('collision', d3.forceCollide().radius(d =>
          d.category === 'course' ? 50 :
          d.category === 'chapter' ? 40 : 30
        ));

      // 创建连接线
      const link = g.append('g')
        .attr('class', 'links')
        .selectAll('line')
        .data(validLinks)
        .join('line')
        .attr('stroke', '#999')
        .attr('stroke-opacity', 0.6)
        .attr('stroke-width', d => d.relation === 'prerequisite' ? 3 : 1)
        .attr('stroke-dasharray', d => d.relation === 'prerequisite' ? null : '5,5');

      // 创建节点组
      const node = g.append('g')
        .attr('class', 'nodes')
        .selectAll('g')
        .data(localGraphData.value.nodes)
        .join('g')
        .call(drag(simulation.value));

      // 添加节点圆形
      node.append('circle')
        .attr('r', d => {
          if (d.category === 'course') return 40;
          if (d.category === 'chapter') return 30;
          return 20;
        })
        .attr('fill', d => {
          if (d.category === 'course') return '#1890ff'; // 蓝色表示课程
          if (d.category === 'chapter') return '#52c41a'; // 绿色表示章节
          return '#faad14'; // 黄色表示知识点
        })
        .attr('stroke', '#fff')
        .attr('stroke-width', 2);

      // 添加文本
      const textNodes = node.append('text')
        .attr('dy', 4)
        .attr('text-anchor', 'middle')
        .attr('fill', '#333')
        .attr('font-size', d => {
          if (d.category === 'course') return '14px';
          if (d.category === 'chapter') return '12px';
          return '10px';
        })
        .attr('font-weight', d => d.category === 'course' ? 'bold' : 'normal');

      // 分行显示文本
      textNodes.each(function(d) {
        const text = d3.select(this);
        const words = d.name.split(/(?<=[\u4e00-\u9fa5])/g); // 中文分词
        let line = '';
        let lineNumber = 0;
        const lineHeight = 1.1;
        const maxLength = d.category === 'course' ? 8 :
                          d.category === 'chapter' ? 6 : 4;

        for (let i = 0; i < words.length; i++) {
          const testLine = line + words[i];
          if (testLine.length > maxLength && i > 0) {
            text.append('tspan')
              .attr('x', 0)
              .attr('y', 0)
              .attr('dy', (lineNumber * lineHeight - (lineHeight * 0.5)) + 'em')
              .text(line);
            line = words[i];
            lineNumber++;
          } else {
            line = testLine;
          }
        }

        text.append('tspan')
          .attr('x', 0)
          .attr('y', 0)
          .attr('dy', (lineNumber * lineHeight - (lineHeight * 0.5)) + 'em')
          .text(line);
      });

      // 添加类型标签
      node.append('text')
        .attr('dy', d => {
          const radius = d.category === 'course' ? 40 :
                         d.category === 'chapter' ? 30 : 20;
          return radius + 12;
        })
        .attr('text-anchor', 'middle')
        .text(d => {
          if (d.category === 'course') return '课程';
          if (d.category === 'chapter') return '章节';
          return '知识点';
        })
        .attr('fill', '#666')
        .attr('font-size', '10px');

      // 更新位置
      simulation.value.on('tick', () => {
        // 约束节点位置在可视区域内
        localGraphData.value.nodes.forEach(d => {
          const radius = d.category === 'course' ? 40 :
                         d.category === 'chapter' ? 30 : 20;
          d.x = Math.max(radius, Math.min(width - radius, d.x));
          d.y = Math.max(radius, Math.min(height - radius, d.y));
        });

        link
          .attr('x1', d => d.source.x)
          .attr('y1', d => d.source.y)
          .attr('x2', d => d.target.x)
          .attr('y2', d => d.target.y);

        node.attr('transform', d => `translate(${d.x},${d.y})`);
      });

      // 添加缩放功能
      const zoom = d3.zoom()
        .extent([[0, 0], [width, height]])
        .scaleExtent([0.2, 3])
        .on('zoom', (event) => {
          g.attr('transform', event.transform);
        });

      svg.call(zoom);

      // 添加提示信息
      node.append('title')
        .text(d => {
          if (d.category === 'course') return `${d.name}\n课程`;
          if (d.category === 'chapter') return `${d.name}\n章节`;
          return `${d.name}\n知识点`;
        });
    }

    // 拖动行为
    const drag = (simulation) => {
      function dragstarted(event) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        event.subject.fx = event.subject.x;
        event.subject.fy = event.subject.y;
      }

      function dragged(event) {
        event.subject.fx = event.x;
        event.subject.fy = event.y;
      }

      function dragended(event) {
        if (!event.active) simulation.alphaTarget(0);
        event.subject.fx = null;
        event.subject.fy = null;
      }

      return d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended);
    }

    // 初始化
    onMounted(() => {
      console.log("KnowledgeGraph组件已挂载");
      loadGraphData();
      renderGraph();

      // 添加窗口大小变化监听
      window.addEventListener('resize', handleResize);
    });

    // 处理窗口大小变化
    const handleResize = () => {
      if (graphContainer.value) {
        renderGraph();
      }
    };

    // 组件卸载时清理
    onUnmounted(() => {
      if (simulation.value) {
        simulation.value.stop();
      }
      window.removeEventListener('resize', handleResize);
    });

    // 监听props变化
    watch(() => props.graphData, () => {
      console.log("graphData props变化，重新加载数据");
      loadGraphData();
      renderGraph();
    }, { deep: true });

    watch(() => props.subject, () => {
      if (!props.graphData || !props.graphData.nodes || props.graphData.nodes.length === 0) {
        console.log("subject props变化且无graphData，使用subject数据");
        loadGraphData();
        renderGraph();
      }
    });

    return {
      graphContainer
    };
  }
};
</script>

<style scoped>
.knowledge-graph-container {
  width: 100%;
  height: 100%;
  background-color: #f9f9f9;
  border-radius: 4px;
  position: relative;
}

.knowledge-graph-container svg {
  display: block;
  width: 100%;
  height: 100%;
}

.knowledge-graph-container text {
  pointer-events: none;
  user-select: none;
}

.empty-graph-message {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #999;
  font-size: 16px;
}
</style>

